/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators;


import com.inspur.edp.bef.bemanager.codegenerator.JavaCompCodeNames;
import com.inspur.edp.bef.bemanager.generatecomponent.GspMetadataExchangeUtil;
import com.inspur.edp.bef.bemanager.util.CheckInfoUtil;
import com.inspur.edp.bef.bizentity.beenum.BEOperationType;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.component.base.GspComponent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.Objects;

/**
 * 构件元数据生成器基类
 */
public abstract class BaseComponentGenerator {

  /**
   * 业务实体编号
   */
  protected String bizEntityCode;
  /**
   * 业务实体程序集名称
   */
  protected String assemblyName;
  protected String nameSpace;
  /**
   * 是否当前生成的构件为子节点的构件
   */
  protected boolean isChildObj;
  /**
   * 节点编号
   */
  protected String objCode;
  protected String bizObjectID;
  /**
   * 原始构件
   */
  protected GspComponent originalComponent;

  /**
   * 生成构件元数据
   *
   * @param operation     业务操作
   * @param path          生成指定路径
   * @param bizEntityCode 业务实体编号
   * @param assemblyName  业务实体程序集名称
   * @param isChildObj    是否子节点
   * @param objCode       节点对象编号
   * @param bizObjectID   业务对象ID
   * @param metadata      元数据
   */
  public final String generateComponent(BizOperation operation, String path, String bizEntityCode,
      String assemblyName, boolean isChildObj, String objCode, String bizObjectID,
      GspMetadata metadata, String defaultNameSpace) {
    this.bizEntityCode = bizEntityCode;
    this.assemblyName = assemblyName;
    this.nameSpace = defaultNameSpace;
    this.isChildObj = isChildObj;
    this.objCode = objCode;
    this.bizObjectID = bizObjectID;
    if (CheckInfoUtil.checkNull(operation.getComponentId())) {
      GspMetadata compMetadata = createComponent(operation, path);
      operation.setComponentId(((GspComponent) compMetadata.getContent()).getComponentID());
      operation.setComponentName(compMetadata.getHeader().getCode());
      addReference(metadata, compMetadata);
      return operation.getCode();
    } else {
      modifyComponent(operation, path);
    }
    return null;
  }

  public GspMetadata createComponent(BizOperation operation, String path, String bizEntityCode,
      String assemblyName, boolean isChildObj, String objCode, String bizObjectID,
      String defaultNameSpace) {
    Objects.requireNonNull(operation, "operation");
    Objects.requireNonNull(path, "path");
    Objects.requireNonNull(bizEntityCode, "bizEntityCode");
    Objects.requireNonNull(assemblyName, "assemblyName");
    Objects.requireNonNull(objCode, "objCode");
    Objects.requireNonNull(bizObjectID, "bizObjectID");
    Objects.requireNonNull(defaultNameSpace, "defaultNameSpace");

    this.bizEntityCode = bizEntityCode;
    this.assemblyName = assemblyName;
    this.nameSpace = defaultNameSpace;
    this.isChildObj = isChildObj;
    this.objCode = objCode;
    this.bizObjectID = bizObjectID;
    return createComponent(operation, path);
  }

  /**
   * 新建构件
   */
  private GspMetadata createComponent(BizOperation operation, String path) {
    //1、构建实体
    GspComponent component = buildComponent();
    //2、赋值
    evaluateComponentInfo(component, operation, null);
    //3、生成构件
    GspMetadata compMetadata = establishComponent(component, path);

    return compMetadata;
  }

  private void addReference(GspMetadata refSrc, GspMetadata refTarget) {
    MetadataReference compReference = new MetadataReference();
    compReference.setMetadata(refSrc.getHeader());
    compReference.setDependentMetadata(refTarget.getHeader());
    refSrc.getRefs().add(compReference);
  }

  /**
   * 获得Java模版Package名称
   *
   * @param
   * @return
   */
  protected final String JavaModuleImportPackage(String packageName) {
    String[] strArray = packageName.split("[.]", -1);
    String str = "com.";
    int i;

    for (i = 0; i < strArray.length; i++) {
      str += strArray[i].toLowerCase() + ".";
    }
    return str;
  }

  /**
   * 获得Java模版类的名称
   *
   * @param classNamestr
   * @param packageNameStr
   * @return
   */
  protected final String JavaModuleClassName(String classNamestr, String packageNameStr) {
    String connections = "";
    if (!CheckInfoUtil.checkNull(classNamestr)) {
      connections = classNamestr.substring(classNamestr.lastIndexOf('.'));
      connections = String.format("%1$s%2$s", packageNameStr, connections);
    }

    return (connections);
  }

  /**
   * 构造构件实体类
   *
   * @return 构件实体类
   * <see cref="GspComponent"/>
   */
  protected abstract GspComponent buildComponent();

  /**
   * 为构件赋值
   *
   * @param component 构件实体信息
   * @param operation 动作信息
   */
  protected abstract void evaluateComponentInfo(GspComponent component, BizOperation operation,
      GspComponent originalComponent);

  /**
   * 生成构件实体对应的构件元数据
   *
   * @param component 构件实体
   * @param path      生成构件元数据指定路径
   * @return 生成的构件元数据名称
   * <see cref="string"/>
   */
  private GspMetadata establishComponent(GspComponent component, String path) {
    return GspMetadataExchangeUtil.getInstance()
        .establishGspMetdadata(component, path, this.bizEntityCode, this.bizObjectID,
            this.nameSpace);
  }

  /**
   * 修改构件
   *
   * @param operation
   * @param path
   */
  private void modifyComponent(BizOperation operation, String path) {
    //1、构建实体
    GspComponent component = buildComponent();

    //3、获取要修改的构件元数据完整路径（包括后缀）
    String fullPath = "";

    ///#region ----------- 兼容旧版本命名规则（此种情况适用于构件名称未修改）--------------
    MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);

    // 得到具体类型的构件扩展名
    String cmpExtendName = evaluateCompTypeExtendNameByOpType(operation.getOpType());
    // 带针对不同类型构件的扩展名的文件全名
    String metadataFileNameWithExtendName =
        operation.getComponentName() + JavaCompCodeNames.ComponentExtensionName;

    if (metadataService.isMetadataExist(path, metadataFileNameWithExtendName)) {
      //TODO
      String[] arrName = operation.getComponentName().split("[_]", -1);
      String strName = "";
      if (arrName[0].equalsIgnoreCase("cmp")) {
        strName = operation.getComponentName().substring(4);
      }
      String oldFileNameWithExtendName = metadataFileNameWithExtendName;
      String newFileNameWithExtendName = metadataFileNameWithExtendName = strName + cmpExtendName;

      metadataService.renameMetadata(oldFileNameWithExtendName, newFileNameWithExtendName, path);
      operation.setComponentName(strName);
      fullPath = path + "\\" + newFileNameWithExtendName;
    } else {
      metadataFileNameWithExtendName = operation.getComponentName() + cmpExtendName;
      if (!metadataService.isMetadataExist(path, metadataFileNameWithExtendName)) {
        throw new RuntimeException("构件元数据" + metadataFileNameWithExtendName + "不存在！");
      }
      fullPath = path + "\\" + operation.getComponentName() + cmpExtendName;
    }

    ///#endregion ---------------------------兼容旧版本---------------------------

    GspComponent originalComponent = getOriginalComponent(path, metadataFileNameWithExtendName);
    //2、赋值
    evaluateComponentInfo(component, operation, originalComponent);
    //component.GetMethod().JavaPackageName = ;
    //component.GetMethod().JavaClassName = ;
    //4、修改更新构件元数据
    GspMetadataExchangeUtil.getInstance()
        .UpdateGspMetadata(component, fullPath, this.bizEntityCode, this.bizObjectID,
            this.nameSpace);
  }

  /**
   * 获取修改元数据之前的元数据信息
   *
   * @param path
   * @param
   * @param metadataFileNameWithSuffix
   * @return
   */
  private GspComponent getOriginalComponent(String path, String metadataFileNameWithSuffix) {
    MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
    GspMetadata metadata = metadataService.loadMetadata(metadataFileNameWithSuffix, path);
    //TODO GspComponentMetadata 对应J版无对应的类，确认一下是否还需要
//		if (metadata.getContent() instanceof GspComponentMetadata)
//		{
//			ComponentSerializer serializer = new ComponentSerializer();
//			Object tempVar = ((IMetadataContentSerializer)((serializer instanceof IMetadataContentSerializer) ? serializer : null)).DeSerialize((JObject)JToken.Parse(((GspComponentMetadata)((metadata.Content instanceof GspComponentMetadata) ? metadata.Content : null)).ContentString));
//			GspComponent originalComponent = (GspComponent)((tempVar instanceof GspComponent) ? tempVar : null);
//			return originalComponent;
//		}
//		else
//		{
    GspComponent originalComponent = (metadata.getContent() instanceof GspComponent)
        ? metadata.getContent() : null;
    return originalComponent;
//		}
  }

  private String evaluateCompTypeExtendNameByOpType(BEOperationType opType) {
    switch (opType) {
      case BizAction:
        return JavaCompCodeNames.BECmpExtendName;
      case BizMgrAction:
        return JavaCompCodeNames.BEMgrCmpExtendName;
      case Determination:
        return JavaCompCodeNames.DtmCmpExtendName;
      case Validation:
        return JavaCompCodeNames.ValCmpExtendName;
      default:
        throw new RuntimeException("未知构件类型");
    }
  }
}
